La totalité des données provient de l’export des données slack (.zip) disponible ici: https://zqsd.slack.com/services/export
Repo git: https://github.com/B3nZ3n/SlackReports
allUsers <- fromJSON("../input/users.json" , flatten = TRUE) %>%
as.data.frame()
On ne garde que les users non supprimés et on exclu les bots. On ne conserve que les colonnes id, name, real_name et color
keeps <- c("id", "name", "real_name", "color")
allUsers <- allUsers[!allUsers$deleted & !allUsers$is_bot , keeps]
head(allUsers)
## id name real_name color
## 1 U03JKQTDX logs Logs 4bbe2e
## 2 U03JMNC9J paf Julien 9f69e7
## 3 U03JMQH0A b3nz3n B3nZ3n e7392d
## 4 U03JN1BGE qn7o Anto Mrb 3c989f
## 5 U03JSCX10 gawel Ga ' ' l 674b1b
## 6 U03JSENHL roux Roux e96699
On enrichi les données pour qu’elles soient directement exploitables et on extrait les données de couleur qui seront utilisées plus tard dans tous les charts
#ajout du "#" devant le code couleur
allUsers$color <- paste0("#", allUsers$color)
colors <- allUsers[!allUsers$color == "#NA", c("name", "color")]
plotColors <- colors$color
names(plotColors) <- colors$name
rm(colors)
head(plotColors)
## logs paf b3nz3n qn7o gawel roux
## "#4bbe2e" "#9f69e7" "#e7392d" "#3c989f" "#674b1b" "#e96699"
On commence par lister tous les fichiers présents dans le dossier general
files <- list.files(path = "../input/general", full.names = TRUE)
files <- files[order(files)]
length(files)
## [1] 2516
On extrait ensuite les données de chaque fichier (un par jour, depuis 2015). Pour ce faire on définit une fonction qui va prendre en entrée le nom du fichier et retourner un data frame contenant les données de ce jour
extractFileContent <- function(filename) {
messages <- fromJSON(filename, flatten = TRUE)
messages %>%
select(one_of(
c(
"client_msg_id",
"type",
"text",
"user",
"ts",
"reply_users",
"reactions"
)
)) %>%
as.data.frame()
}
On applique ensuite cette fonction sur toute la liste des fichiers (uniquement si le dataframe allMessage n’existe pas déjà dans le dossier data dû à un chargement antérieur).
On enrichit/manipule ensuite les données et on enregistre le tout dans un fichier pour éviter de re-charger tous les fichiers à chaque run si on les a déj
if (!file.exists("../data/all_Messages.rds")) {
allMessages <- sapply(files, FUN = extractFileContent)
#on "applatit" le dataset
allMessages <- rbindlist(allMessages, fill = TRUE)
#on converti les timestamps en date
allMessages$ts = as_datetime(as.integer(allMessages$ts))
#on ajoute une colonne qui contient le "vrai" nom sur base de l'ID.
allMessages$username <-
with(allUsers, name[match(allMessages$user, id)])
#on ne garde que les messages des users que l'on a conservé lors de l'étape d'extraction des users
allMessages <- allMessages[allMessages$user %in% allUsers$id,]
#on ne garde que les données de l'année 2021
allMessages <-
allMessages[allMessages$ts >= '2021-01-01 00:00:00' &
allMessages$ts <= '2021-12-31 00:00:00' ,]
#on enregistre le dataframe allMessages
saveRDS(allMessages, file = "../data/all_Messages.rds")
} else{
#si on a déja chargé précédemment, on charge directement le dataframe
allMessages <- readRDS(file = "../data/all_Messages.rds")
}
#on ne garde que les messages qui ont eu une réponse (thread)
threads <-
allMessages[!allMessages$reply_users == "NULL", c("username", "reply_users")]
#on expand la liste des users contenus dans reply_users
threads <- tidyr::unnest(threads, cols = reply_users)
#on aggrège le nombre de replies par user
threads %>% group_by(username, reply_users) %>%
summarise(count_replies = n()) -> threads
#on lookup et remplace les valeurs d'ID des users par leur vrai nom
threads$reply_users <-
with(allUsers, name[match(threads$reply_users, id)])
#pour ne pas surcharger le chart on ne garde que les usernames qui ont eu plus que 5 replies
threads <- threads[threads$count_replies > 5, ]
#définition des charts
ggplot(threads,
aes(axis1 = username,
axis2 = reply_users,
y = count_replies)) +
geom_alluvium(
aes(fill = username),
curve_type = "sigmoid",
width = 1 / 10,
alpha = 0.7
) +
geom_stratum(width = 1 / 10) +
geom_text(stat = "stratum",
aes(label = paste(after_stat(stratum)))) +
scale_x_discrete(limits = c("username", "reply_users"),
expand = c(.1, .1)) +
scale_fill_manual(values = plotColors) +
ggtitle("Nombre de messages envoyés par \"reply_users\" dans un thread créé par \"user\"") +
theme(legend.position = "none")
p <- ggplot(threads,
aes(x = username,
y = reply_users,
fill = count_replies)) +
geom_tile()+
ggtitle("Nombre de messages envoyés par \"reply_users\" dans un thread créé par \"user\"")+
theme(axis.text.x = element_text(angle = -90, hjust = 0))
ggplotly(p,
width = 800,
height = 600)
reactions <-
allMessages[!allMessages$reactions == "NULL", c("user", "reactions")]
reactions <- tidyr::unnest(reactions, cols = reactions)
reactions <- reactions[, c("user", "name", "count")]
reactions %>% group_by(user, name) %>%
summarise(count_reaction = sum(count)) -> reactions
reactions$user <- with(allUsers, name[match(reactions$user, id)])
reactions %>% group_by(name) %>% summarise(sum(count_reaction)) %>% top_n(n = 10) -> top10emojii
reactions <- reactions[reactions$name %in% top10emojii$name, ]
p <-ggplot(data = reactions, aes(name, count_reaction, fill = user)) +
geom_bar(stat = 'identity') +
scale_fill_manual(values = plotColors) +
ggtitle("Emojii usage per user") +
xlab("emojii") +
ylab("Number of uses") +
theme(axis.text.x = element_text(angle = -90, hjust = 0))
ggplotly(p,
width = 800,
height = 600)
p <- ggplot(reactions,
aes(x =name ,
y = user,
fill = count_reaction)) +
geom_tile()+
ggtitle("todo")+
theme(axis.text.x = element_text(angle = -90, hjust = 0))
ggplotly(p,
width = 800,
height = 600)
jokeScores <-
rev(
c(
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"height",
"nine",
"keycap_ten"
)
)
jokeColors <-
rev(
c(
"#FF0000",
"#dd776e",
"#e2886c",
"#e79a69",
"#ecac67",
"#e9b861",
"#f5ce62",
"#d4c86a",
"#b0be6e",
"#94bd77",
"#73b87e"
)
)
names(jokeColors) <- jokeScores
reactions <-
allMessages[!allMessages$reactions == "NULL", c("user", "reactions")]
reactions <- tidyr::unnest(reactions, cols = reactions)
reactions <- reactions[, c("user", "name", "count")]
reactions %>% group_by(user, name) %>%
summarise(count_reaction = sum(count)) -> reactions
reactions$user <- with(allUsers, name[match(reactions$user, id)])
reactions <- reactions[reactions$name %in% jokeScores, ]
reactions$name <- ordered(reactions$name, levels = names(jokeColors))
p <- ggplot(data = reactions, aes(
x = user,
y = count_reaction,
fill = name,
order = name
)) +
geom_bar(stat = 'identity') +
scale_fill_manual("", values = jokeColors) +
ggtitle("Les plus rigolos? depuis 2015") +
xlab("username") +
ylab("score") +
theme(axis.text.x = element_text(angle = -90, hjust = 0))
ggplotly(p,
width = 800,
height = 600)
#ne garder que les messages contenant un "@" vers un user
allMessages %>% filter(str_detect(text, "<@.*>")) -> pings
#extraire le ou les users pingés dans une nouvelle colonne
pings$pinged <- str_extract_all(pings$text, "(?<=<@).{9}")
#on expand la liste des users contenus dans pinged
pings <- tidyr::unnest(pings, cols = pinged)
pings <- pings[!pings$username == "NA",c("username","pinged")]
pings$pinged <- with(allUsers, name[match(pings$pinged, id)])
#on aggrège le nombre de ping par user
pings %>% group_by(username, pinged) %>%
summarise(count_ping = n()) -> pings
p <- ggplot(pings,
aes(x =pinged ,
y = username ,
fill = count_ping)) +
geom_tile()+
ggtitle("todo")+
theme(axis.text.x = element_text(angle = -90, hjust = 0))
ggplotly(p,
width = 800,
height = 600)
source(file = “services/deploy-to-s3.R”, encoding = “utf-8”) mustDeploy = Sys.getenv(“ZQSD_REPORT_MUST_DEPLOY”) == “true” if (mustDeploy) { printf(“Deploying to S3…”) uploadHtmlFile() } else { printf(“Do not deploy”) }